home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / gr564s.zip / SRC / MS / DIRENT.C < prev    next >
C/C++ Source or Header  |  1993-08-27  |  10KB  |  395 lines

  1. /*
  2.  *  dirent.c - POSIX directory access routines for MS-DOS, OS/2 and Windows/NT
  3.  *
  4.  *  Author: Frank Whaley (few@autodesk.com)
  5.  *
  6.  *  Copyright Frank Whaley 1993.  All rights reserved.
  7.  *
  8.  *  Permission to use, copy, modify, distribute, and sell this software
  9.  *  and its documentation for any purpose is hereby granted without fee,
  10.  *  provided that the above copyright notice appears in all copies of the
  11.  *  source code.  The name of the author may not be used to endorse or
  12.  *  promote products derived from this software without specific prior
  13.  *  written permission.
  14.  *
  15.  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  *  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  *
  19.  *  CAVEATS:
  20.  *    The associated 'dirent.h' file should be copied into your system
  21.  *    include directory if the '#include <dirent.h>' syntax will be used,
  22.  *    otherwise a '-I.' switch must be added to command lines.
  23.  *
  24.  *    This code was originally developed with Turbo C, and continues to
  25.  *    use TC's function and structure names.  Numerous macros make the
  26.  *    code palatable to MSC 5.1/6.0 for MS-DOS and OS/2.  The macros
  27.  *    depend on four defines: __TURBOC__, __MSC__, __MSDOS__, and __OS2__.
  28.  *    The TC and BC compilers provide __TURBOC__ and __MSDOS__ as
  29.  *    appropriate; MSC doesn't provide any of these flags so they must
  30.  *    be given on the command line.  Sample commands for building test
  31.  *    programs (see '#ifdef TEST' below):
  32.  *      tcc -DTEST dirent.c
  33.  *      bcc -DTEST dirent.c
  34.  *      cl -DTEST -D__MSC__ -D__MSDOS__ dirent.c
  35.  *      cl -Lp -DTEST -D__MSC__ -D__OS2__ dirent.c
  36.  *      cl -DTEST -D__MSC__ -D__NT__ dirent.c
  37.  *
  38.  *    This code reads an entire directory into memory, and thus is not
  39.  *    a good choice for scanning very large directories.  The maximum
  40.  *    number of names allowed is controlled by MAXNAMES, defined below.
  41.  *    This value is used to allocate an array of pointers, so making it
  42.  *    ridiculously large may cause the code to fail silently.  The array
  43.  *    of pointers could be realloc()'ed in the loadDir() function, but
  44.  *    this can be dangerous with some 'weak' memory allocation packages.
  45.  *
  46.  *    POSIX requires that the rewinddir() function re-scan the directory,
  47.  *    so this code must preserve the original directory name.  If the
  48.  *    name given is a relative path (".", "..", etc.) and the current
  49.  *    directory is changed between opendir() and rewinddir(), a different
  50.  *    directory will be scanned by rewinddir().  (The directory name
  51.  *    could be "qualified" by opendir(), but this process yields unusable
  52.  *    names for network drives).
  53.  *
  54.  *    This code provides only file names, as that is all that is required
  55.  *    by POSIX.  Considerable other information is available from the
  56.  *    MS-DOS and OS/2 directory search functions.  This package should not
  57.  *    be considered as a general-purpose directory scanner, but rather as
  58.  *    a tool to simplify porting other programs.
  59.  */
  60.  
  61. #include <stdio.h>
  62. #include <stdlib.h>
  63. #include <errno.h>
  64. #include <io.h>
  65. #include <string.h>
  66. #include <dirent.h>
  67.  
  68. #define MAXNAMES    1024        /*  max names in dir list  */
  69. #define MAXLEN        260        /*  max len of any path/filename  */
  70.  
  71. #define NULLP(type)    ((type *)0)    /*  readability macro  */
  72.  
  73. #ifdef __TURBOC__
  74. #include <alloc.h>
  75. #include <dir.h>
  76. #include <mem.h>
  77. typedef struct ffblk    FIND_T;
  78. #define findclose(f)
  79. #define FA_RDONLY    0x01
  80. #define FA_HIDDEN    0x02
  81. #define FA_SYSTEM    0x04
  82. #define FA_LABEL    0x08
  83. #define FA_DIREC    0x10
  84. #define FA_ARCH        0x20
  85. #endif /*__TURBOC__*/
  86.  
  87. #if defined(__MSC__) && defined(__MSDOS__)
  88. #include <dos.h>
  89. #include <malloc.h>
  90. #include <memory.h>
  91. typedef struct find_t    FIND_T;
  92. #define findfirst(n,f,a)    _dos_findfirst(n,a,f)
  93. #define findnext(f)        _dos_findnext(f)
  94. #define findclose(f)
  95. #define ff_name            name
  96. #define FA_RDONLY        _A_RDONLY
  97. #define FA_HIDDEN        _A_HIDDEN
  98. #define FA_SYSTEM        _A_SYSTEM
  99. #define FA_LABEL        _A_VOLID
  100. #define FA_DIREC        _A_SUBDIR
  101. #define FA_ARCH            _A_ARCH
  102. #endif /*__MSC__&&__MSDOS__*/
  103.  
  104. #if defined(__MSC__) && defined(__OS2__)
  105. #define INCL_DOS
  106. #include <os2.h>
  107. #include <malloc.h>
  108. #include <memory.h>
  109. typedef struct
  110. {
  111.     HDIR ft_handle;
  112.     FILEFINDBUF ft_ffb;
  113.     int ft_count;
  114. } FIND_T;
  115. #define findfirst(n,f,a)    ((f)->ft_handle=0xFFFF,(f)->ft_count=1,\
  116.                     DosFindFirst(n,&(f)->ft_handle,a,\
  117.                     &(f)->ft_ffb,sizeof((f)->ft_ffb),\
  118.                     &(f)->ft_count,0L))
  119. #define findnext(f)        DosFindNext((f)->ft_handle,&(f)->ft_ffb,\
  120.                     sizeof((f)->ft_ffb),&(f)->ft_count)
  121. #define findclose(f)        DosFindClose((f)->ft_handle);
  122. #define ff_name            ft_ffb.achName
  123. #define FA_RDONLY        0x01
  124. #define FA_HIDDEN        0x02
  125. #define FA_SYSTEM        0x04
  126. #define FA_LABEL        0x08
  127. #define FA_DIREC        0x10
  128. #define FA_ARCH            0x20
  129. #endif /*__MSC__&&__OS2__*/
  130.  
  131. #if defined(__MSC__) && defined(__NT__)
  132. #include <windows.h>
  133. typedef struct
  134. {
  135.     long ft_hdl;
  136.     struct _finddata_t ft_ffb;
  137. } FIND_T;
  138.  
  139. #define findfirst(n,f,a)    (((f)->ft_hdl=_findfirst(n,&(f)->ft_ffb))==-1)
  140. #define findnext(f)        _findnext((f)->ft_hdl,&(f)->ft_ffb)
  141. #define findclose(f)        _findclose((f)->ft_hdl)
  142. #define ff_name            ft_ffb.name
  143. #define FA_RDONLY        0x01
  144. #define FA_HIDDEN        0x02
  145. #define FA_SYSTEM        0x04
  146. #define FA_LABEL        0x08
  147. #define FA_DIREC        0x10
  148. #define FA_ARCH            0x20
  149. #endif /*__MSC__&&__NT__*/
  150.  
  151.     /*  mask for all interesting files  */
  152. #define ALL    (FA_RDONLY+FA_HIDDEN+FA_SYSTEM+FA_DIREC)
  153.  
  154. typedef struct __DIRENT
  155. {
  156.     char path[MAXLEN];    /*  directory name  */
  157.     char **names;        /*  array of ptrs to names  */
  158.     int count;        /*  number of entries  */
  159.     int current;        /*  current entry  */
  160. } DIRENT;
  161.  
  162.     /*  forward declarations  */
  163. static int loadDir(DIRENT *dir);
  164.  
  165. /*
  166. -*    opendir - open a directory for reading
  167.  */
  168.     DIR *
  169. opendir(char const *name)
  170. {
  171.     DIRENT *dir;
  172.  
  173.     /*  worth looking at ??  */
  174.     if ( (name == NULL) || (*name == '\0') )
  175.     {
  176.         errno = ENOENT;
  177.         return ( NULLP(DIR) );
  178.     }
  179.  
  180.     /*  get space for DIRENT struct  */
  181.     if ( (dir = malloc(sizeof(DIRENT))) == NULLP(DIRENT) )
  182.     {
  183.         errno = ENOMEM;
  184.         return ( NULLP(DIR) );
  185.     }
  186.  
  187.     /*  load the names  */
  188.     strcpy(dir->path, name);
  189.     if ( !loadDir(dir) )
  190.     {
  191.         free(dir);
  192.         /*  errno already set  */
  193.         return ( NULLP(DIR) );
  194.     }
  195.  
  196.     return ( (DIR *)dir );
  197. }
  198.  
  199. /*
  200. -*    closedir - close a directory
  201.  */
  202.     int
  203. closedir(DIR *dir)
  204. {
  205.     char **names = ((DIRENT *)dir)->names;
  206.     int count = ((DIRENT *)dir)->count;
  207.  
  208.     while ( count )
  209.         free(names[--count]);
  210.     free(names);
  211.     free(dir);
  212.     return ( 0 );
  213. }
  214.  
  215. /*
  216. -*    readdir - return ptr to next directory entry
  217.  */
  218.     struct dirent *
  219. readdir(DIR *dir)
  220. {
  221.     static struct dirent dp;
  222.     DIRENT *de = (DIRENT *)dir;
  223.  
  224.     if ( de->current >= de->count )
  225.         return ( NULLP(struct dirent) );
  226.  
  227.     strcpy(dp.d_name, de->names[de->current++]);
  228.     return ( &dp );
  229. }
  230.  
  231. /*
  232. -*    rewinddir - rewind directory (re-open)
  233.  */
  234.     void
  235. rewinddir(DIR *dir)
  236. {
  237.     char **names = ((DIRENT *)dir)->names;
  238.     int count = ((DIRENT *)dir)->count;
  239.  
  240.     /*  free existing names  */
  241.     while ( count )
  242.         free(names[--count]);
  243.     free(names);
  244.     /*  reload  */
  245.     loadDir((DIRENT *)dir);
  246. }
  247.  
  248. /*
  249. -*    __seekdir - change directory position
  250.  */
  251.     void
  252. __seekdir(DIR *dir, long off)
  253. {
  254.     DIRENT *de = (DIRENT *)dir;
  255.  
  256.     if ( (off < 0) || (off > de->count) )
  257.         return;
  258.     de->current = (int)off;
  259. }
  260.  
  261. /*
  262. -*    __telldir - return current directory position
  263.  */
  264.     long
  265. __telldir(DIR *dir)
  266. {
  267.     return ( (long)((DIRENT *)dir)->current );
  268. }
  269.  
  270.     /*  LOCAL ROUTINES  */
  271. /*  load a directory list  */
  272.     int
  273. loadDir(DIRENT *dir)
  274. {
  275.     char pattern[MAXLEN];
  276.     char **names;
  277.     int count = 0;
  278.     int mode;
  279.     FIND_T ff;
  280.  
  281.     /*  do we have just a drive name ??  */
  282.     if ( (dir->path[1] == ':') && (dir->path[2] == '\0') )
  283.         strcat(dir->path, ".");
  284.  
  285.     /*  is it a directory ??  */
  286. #ifdef __MSDOS__
  287. #ifdef __TURBOC__
  288.     if ( ((mode = _chmod(dir->path, 0)) < 0) ||
  289. #endif /*__TURBOC__*/
  290. #ifdef __MSC__
  291.     if ( _dos_getfileattr(dir->path, &mode) ||
  292. #endif /*__MSC__*/
  293. #endif /*__MSDOS__*/
  294. #ifdef __OS2__
  295.     if ( DosQFileMode(dir->path, &mode, 0L) ||
  296. #endif /*__OS2__*/
  297. #ifdef __NT__
  298.     if ( ((mode = GetFileAttributes(dir->path)) == 0xFFFFFFFF) ||
  299. #endif /*__NT__*/
  300.          !(mode & FA_DIREC) )
  301.     {
  302.         errno = ENOTDIR;
  303.         return ( 0 );
  304.     }
  305.  
  306.     /*  get space for array of ptrs  */
  307.     if ( (names = (char **)malloc(MAXNAMES * sizeof(char *))) ==
  308.                                 NULLP(char *) )
  309.     {
  310.         errno = ENOMEM;
  311.         return ( 0 );
  312.     }
  313.  
  314.     /*  build pattern string  */
  315.     strcpy(pattern, dir->path);
  316.     if ( strchr("\\/:", pattern[strlen(pattern) - 1]) == NULL )
  317.         strcat(pattern, "/");
  318.     strcat(pattern, "*.*");
  319.  
  320.     if ( !findfirst(pattern, &ff, ALL) )
  321.         do
  322.         {
  323.             /*  add name if not "." or ".."  */
  324.             if ( ff.ff_name[0] != '.' )
  325.             {
  326.                 /*  make a copy of the name  */
  327.                 if ( (names[count] = strdup(ff.ff_name))
  328.                                      == NULL )
  329.                 {
  330.                     /*  free all if error (out of mem)  */
  331.                     while ( count )
  332.                         free(names[--count]);
  333.                     free(names);
  334.                     errno = ENOMEM;
  335.                     return ( 0 );
  336.                 }
  337.                 count++;
  338.             }
  339.         }
  340.         while ( !findnext(&ff) && (count < MAXNAMES) );
  341.     findclose(&ff);
  342.     dir->names = names;
  343.     dir->count = count;
  344.     dir->current = 0;
  345.     return ( 1 );
  346. }
  347.  
  348. #ifdef TEST
  349.     int
  350. main(int argc, char *argv[])
  351. {
  352.     DIR *dir;
  353.     struct dirent *d;
  354.     long pos;
  355.  
  356.     /*  check arguments  */
  357.     if ( argc != 2 )
  358.     {
  359.         fprintf(stderr, "Usage: dirent <directory>\n");
  360.         return ( 1 );
  361.     }
  362.  
  363.     /*  try to open the given directory  */
  364.     if ( (dir = opendir(argv[1])) == (DIR *)0 )
  365.     {
  366.         fprintf(stderr, "cannot open %s\n", argv[1]);
  367.         return ( 1 );
  368.     }
  369.  
  370.     /*  walk the directory once forward  */
  371.     while ( (d = readdir(dir)) != NULLP(struct dirent) )
  372.         printf("%s\n", d->d_name);
  373.  
  374.     /*  rewind  */
  375.     rewinddir(dir);
  376.  
  377.     /*  scan to the end again  */
  378.     while ( (d = readdir(dir)) != NULLP(struct dirent) )
  379.         ;
  380.  
  381.     /*  seek backwards to beginning  */
  382.     for ( pos = __telldir(dir); pos >= 0; pos-- )
  383.     {
  384.         __seekdir(dir, pos);
  385.         printf("%ld=%ld\n", __telldir(dir), pos);
  386.     }
  387.  
  388.     /*  close and exit  */
  389.     printf("closedir() returns %d\n", closedir(dir));
  390.     return ( 0 );
  391. }
  392. #endif /*TEST*/
  393.  
  394. /*  END of dirent.c  */
  395.